import type { IAnswerNavigationItem } from '../../../../../../../../module/page_enhancer/navigation/answer_navigator'
import type { PlatformElementConfig } from '../../../../../../../../types/interfaces'
import { ToolKit } from '../../../../../../../../lib/utils/toolkit'
import { ConfigManager } from '../../../../../../../../module/config_manager'
import { AppModule } from '../../../../../../../../module/config_manager/types'
import { AnswerNavigator } from '../../../../../../../../module/page_enhancer/navigation/answer_navigator'
import { BodyClasses, logger, PROJECT_PREFIX } from '../../../../../../../../types/constants'

export class AnswerListManager {
  private name: string = `AnswerListManager`
  private observer: MutationObserver | null = null
  private processedItems = new WeakSet<Element>()
  private readonly className: string = 'answer-meta'
  readonly selector: string = `.${this.className}`
  readonly dealSelector: string
  readonly highlightClassName: string = `highlighted-animate`
  private navigator: AnswerNavigator
  private configManager: ConfigManager
  private static instance: AnswerListManager

  constructor(private elements: Record<string, PlatformElementConfig>) {
    this.dealSelector = `${this.elements.ANSWERS_CONTAINER.selector} .List-item`
    this.navigator = AnswerNavigator.getInstance()
    this.configManager = ConfigManager.getInstance()

    const enableAnswerNavigator = this.configManager.getFeatureEnabled(AppModule.AnswerNavigator.id)

    if (enableAnswerNavigator) {
      ToolKit.async.delay(3000).then(() => {
        if (!this.navigator?.$element) {
          logger.warn(`[${this.name}] 问答导航器未加载，尝试加载`)
          this.navigator.mount()
        }
        this.navigator.on('navigate', (index) => {
          this.scrollToAnswer(index)
        })
      })
    }

    this.initListObserver()
  }

  /**
   * 获取单例实例
   */
  public static getInstance(elements: Record<string, PlatformElementConfig>): AnswerListManager {
    if (!AnswerListManager.instance) {
      AnswerListManager.instance = new AnswerListManager(elements)
    }

    return AnswerListManager.instance
  }

  private scrollToAnswer(index: number): void {
    const $item = $(`${this.dealSelector}[data-dynamic-index="${index}"]`)

    if ($item.length) {
      // start: 元素顶部与视口顶部对齐
      $item[0].scrollIntoView({ behavior: 'smooth', block: 'start' })
      this.highlightItem($item)
    }
  }

  private highlightItem($item: JQuery<HTMLElement>): void {
    // 清除旧动画防止冲突
    $item.off('animationend').removeClass(this.highlightClassName)

    // 滚动监听器
    const scrollHandler = () => {
      const rect = $item[0].getBoundingClientRect()
      const isVisible = rect.top < window.innerHeight && rect.bottom > 0

      // 当元素进入视口时启动动画
      if (isVisible) {
        $item.addClass(this.highlightClassName)
          .on('animationend', () => {
            $item.removeClass(this.highlightClassName)
          })
        $(window).off('scroll', scrollHandler) // 移除监听
      }
    }

    // 绑定滚动事件
    $(window).on('scroll', scrollHandler)

    // 如果已经在视口中立即触发
    scrollHandler()

    // 5秒后自动清理（防内存泄漏）
    setTimeout(() => {
      $(window).off('scroll', scrollHandler)
      $item.removeClass(this.highlightClassName)
    }, 5000)
  }

  /**
   * 初始化列表观察器
   */
  initListObserver(): void {
    const { ANSWERS_CONTAINER } = this.elements
    const container = document.querySelector(`${ANSWERS_CONTAINER.selector} .List [role="list"]`)

    if (!container)
      return

    // 销毁已有观察器避免重复
    this.dispose()

    // 创建防抖处理器
    const debouncedProcess = ToolKit.func.throttle(() => {
      requestAnimationFrame(() => this.processListItems())
    }, 300)

    // 1. 配置观察器
    this.observer = new MutationObserver((mutations) => {
      if (mutations.some(m => m.addedNodes.length > 0)) {
        debouncedProcess()
        this.updateAnswerSelectors()
      }
    })

    // 2. 启动观察
    this.observer.observe(container, {
      childList: true, // 仅观察直接子节点变化
      subtree: false,
    })

    // 3. 分批次初始化处理
    this.processListItemsChunked()
    this.updateAnswerSelectors()
  }

  /**
   * 分批次处理列表项
   */
  private processListItemsChunked(chunk_size: number = 5): void {
    const items = $(this.dealSelector)

    let processed = 0
    const processNextChunk = () => {
      const chunk = items.slice(processed, processed + chunk_size)
      chunk.each((i, el) => this.processSingleItem(processed + i + 1, el))
      processed += chunk_size

      if (processed < items.length) {
        setTimeout(processNextChunk, 50)
      }
    }

    processNextChunk()
  }

  /**
   * 处理单个列表项
   */
  private processSingleItem(index: number, element: HTMLElement): void {
    if (this.processedItems.has(element))
      return

    try {
      const $item = $(element)
      const updateTime = $item.find('[itemprop="dateModified"]').attr('content')

      // 更新序号（使用dataset避免重绘）
      $item[0].dataset.dynamicIndex = index.toString()

      // 处理时间标记
      if (updateTime) {
        const existingMarker = $item.find(this.selector)[0]
        if (existingMarker) {
          existingMarker.innerHTML = this.getTimeMarkerContent(index, updateTime)
        }
        else {
          $item.prepend(this.createTimeMarker(index, updateTime))
        }
      }

      this.processedItems.add(element)
    }
    catch (error) {
      console.error(`处理第${index}项失败:`, error)
      this.markAsError(element)
    }
  }

  /**
   * 处理列表项
   */
  private processListItems(): void {
    const { ANSWERS_CONTAINER } = this.elements

    // 隐藏广告
    $(`${ANSWERS_CONTAINER.selector} .Pc-word-new`)?.remove()

    // 处理列表项
    $(this.dealSelector).each((index, element) => {
      const $item = $(element)

      // A. 更新序号
      $item.attr('data-dynamic-index', index + 1)

      // B. 处理时间标记
      const updateTime = $item.find('[itemprop="dateModified"]').attr('content')

      if (!updateTime)
        return

      const $timeMarker = $item.find(this.selector)

      // 存在则更新，不存在则创建
      if ($timeMarker.length) {
        $timeMarker.html(this.getTimeMarkerContent(index + 1, updateTime))
      }
      else {
        $item.prepend(this.createTimeMarker(index + 1, updateTime))
      }
    })
  }

  /*
   * 更新导航器选项
   */
  private updateAnswerSelectors(): void {
    const answerItems: IAnswerNavigationItem[] = $(this.dealSelector)
      .filter((_index, el) => !$(el).hasClass('PlaceHolder'))
      .map((i, el) => {
        const $item = $(el)

        // 提取赞同信息
        const voteButton = $item.find('.ContentItem-actions .VoteButton[aria-label*="赞同"]')
        const voteText = voteButton.attr('aria-label')?.trim()

        // 提取评论信息
        const commentButton = $item.find('.ContentItem-actions > .Button:contains("条评论")')
        const commentText = commentButton.text().trim()

        // 提取喜欢信息
        const likeButton = $item.find('.ContentItem-actions > .Button:contains("喜欢")')
        const likeText = likeButton.text().trim()

        // 获取纯文本内容（排除图片）
        const getPureText = (html: string | null | undefined) => {
          if (!html)
            return ''

          const temp = document.createElement('div')
          temp.innerHTML = html

          // 移除所有图片
          temp.querySelectorAll('img, figure').forEach(el => el.remove())

          // 获取纯文本并修剪
          return ToolKit.string.truncate((temp.textContent || '')
            .replace(/\s+/g, ' ')
            .trim(), 200)
        }

        return {
          index: i + 1,
          username: $item.find('.AuthorInfo-name').text().trim(),
          avatar: $item.find('.AuthorInfo-avatar').attr('src'),
          floorCount: `${i + 1}`,
          excerpt: getPureText($item.find('.RichContent-inner').html()),
          voteText,
          voteCount: Number.parseInt($item.find('meta[itemprop="upvoteCount"]').attr('content')?.trim() || '0'),
          commentText,
          commentCount: Number.parseInt($item.find('meta[itemprop="commentCount"]').attr('content')?.trim() || '0'),
          likeText,
          updateTime: $item.find('meta[itemprop="dateModified"]').attr('content')?.trim() || '0',
        } as IAnswerNavigationItem
      })
      .get()

    this.navigator.updateOptions(answerItems)
  }

  /**
   * 创建时间标记元素
   */
  private createTimeMarker(index: number, time: string): JQuery {
    return $(`
      <div class="page-toolbar-container">
        <div class="operate">
          <button class="toggle-height" title="">
            <span class="btn-text">展开</span>
            <svg class="btn-icon" viewBox="0 0 24 24" width="16" height="16">
              <path fill="currentColor" d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"/>
            </svg>
          </button>
        </div>
        <div class="${this.className}" data-time="${time}">
          ${this.getTimeMarkerContent(index, time)}
        </div>
      </div>
    `).on('click', '.toggle-height', this.handleHeightToggle.bind(this))
  }

  /**
   * 生成时间标记内容
   */
  private getTimeMarkerContent(index: number, time: string): string {
    return `
      <span class="answer-floor">#${index}</span>
      <span class="answer-time">${ToolKit.time.formatRelativeTime(time)}</span>
    `
  }

  /**
   * 处理高度切换点击事件
   */
  private handleHeightToggle(event: JQuery.ClickEvent): void {
    event.stopPropagation()

    const $button = $(event.currentTarget)
    const $item = $button.closest('.List-item')

    // 切换状态
    const isExpanded = $item.hasClass('no-height-limit')
    $item.toggleClass('no-height-limit', !isExpanded)

    if (!isExpanded) {
      $item.find('.RichContent').removeClass(BodyClasses.IS_COLLAPSED)
    }

    // 更新按钮状态
    this.updateButtonState($button, !isExpanded)
  }

  /**
   * 更新按钮视觉状态
   */
  private updateButtonState($button: JQuery<HTMLElement>, isExpanded: boolean): void {
    $button.find('.btn-text').text(isExpanded ? '收起' : '展开')
    $button.find('.btn-icon').css('transform', isExpanded ? 'rotate(180deg)' : 'rotate(0)')

    // 更新 ARIA 属性
    $button.attr('aria-expanded', String(isExpanded))
  }

  /**
   * 错误处理
   */
  private markAsError(element: Element): void {
    const $el = $(element)

    $el.addClass('item-error')

    if (!$el.find('.error-fallback').length) {
      $el.prepend('<div class="error-fallback">内容加载异常</div>')
    }
  }

  /**
   * 销毁观察器
   */
  dispose(): void {
    this.observer?.disconnect()
    this.observer = null
    this.processedItems = new WeakSet()
  }

  styles(): string {
    return `
      ${this.navigator.getStyles()}
      
      .List-item {
        &.${this.highlightClassName} {
          animation: highlight-glow 2.5s ease;
        }
        
        /* 高度控制样式 */
        &.no-height-limit .RichContent-inner {
          max-height: unset !important;
          overflow: visible !important;
        }
        
        /* 不同楼层的颜色区分 */
        &:nth-child(6n+1) .answer-floor { background: linear-gradient(135deg, #ff4d4f, #cf1322) !important; }
        &:nth-child(6n+2) .answer-floor { background: linear-gradient(135deg, #fa8c16, #d46b08) !important; }
        &:nth-child(6n+3) .answer-floor { background: linear-gradient(135deg, #52c41a, #389e0d) !important; }
        &:nth-child(6n+4) .answer-floor { background: linear-gradient(135deg, #13c2c2, #08979c) !important; }
        &:nth-child(6n+5) .answer-floor { background: linear-gradient(135deg, #722ed1, #531dab) !important; }
      }

      /* 工具栏容器 */
      .page-toolbar-container {
        position: absolute;
        top: 1rem;
        right: 1rem;
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 4px 8px;
        border-radius: 12px;
        background: var(--${PROJECT_PREFIX}-theme-toolbar-bg);
        box-shadow: 0 2px 8px var(--${PROJECT_PREFIX}-theme-toolbar-shadow-bg);
        line-height: 1;
        backdrop-filter: blur(4px);
        z-index: 1;
        white-space: nowrap !important;
        
        /* 切换按钮 */
        .toggle-height {
          display: inline-flex;
          align-items: center;
          gap: 4px;
          padding: 6px 10px;
          border: none;
          border-radius: 16px;
          background: var(--${PROJECT_PREFIX}-theme-toolbar-button-bg) !important;
          color: var(--${PROJECT_PREFIX}-theme-toolbar-button-text) !important;
          font-size: 13px;
          font-weight: 500;
          cursor: pointer;
          transition: all 0.2s ease;
          
          &:hover {
            background: var(--${PROJECT_PREFIX}-theme-toolbar-button-bg-hover)!important;
          }
        }
        
        /* 楼层标识 */
        .answer-floor {
          display: inline-flex;
          width: 26px;
          height: 26px;
          align-items: center;
          justify-content: center;
          border-radius: 50%;
          background: var(--${PROJECT_PREFIX}-theme-toolbar-answer-floor-bg);
          color: var(--${PROJECT_PREFIX}-theme-toolbar-answer-floor-text) !important;
          font-size: 13px;
          font-weight: 600;
        }
        
        /* 时间文本 */
        .answer-time {
          font-size: 13px;
          font-weight: 500;
          color: var(--${PROJECT_PREFIX}-theme-toolbar-answer-time-text) !important;
        }
      }
    `
  }
}
